Device sampleDevice = JSON.parseObject(str1, Device.class);
在使用 fastjson 將字符串直接反序列化 Java 對象的時候(而不是通過 JSON 一個 feild 一個 feild 的解析來構造 pojo,遇到覆雜對象會很難讓人看懂代碼寫的是啥),遇到了報錯:
Exception in thread "main" com.alibaba.fastjson.JSONException: syntax error, expect {, actual [, pos 105, fieldName fun, fastjson-version 1.2.47
at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:451)
at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:271)
at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:267)
at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:661)
at com.alibaba.fastjson.parser.deserializer.MapDeserializer.parseMap(MapDeserializer.java:192)
at com.alibaba.fastjson.parser.deserializer.MapDeserializer.deserialze(MapDeserializer.java:59)
at com.alibaba.fastjson.parser.deserializer.MapDeserializer.deserialze(MapDeserializer.java:41)
at com.alibaba.fastjson.parser.deserializer.FastjsonASMDeserializer_1_Device.deserialze(Unknown Source)
at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:267)
at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:661)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:365)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:269)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:488)
at serialization_tutorial.main.main(main.java:53)
Process finished with exit code 1
意思大概是 fieldName fun 里面的數據無法正常解析,這是因為 fun 所對應的數據形態是一個 Iterable,導致 fastjson 無法解析。範例代碼如下:
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Device {
@Getter
@Setter
private String deviceNo;
@Getter
@Setter
private GradeWithValue grade;
@Getter
@Setter
private Status Status;
@Getter
@Setter
private String description;
@Getter
@Setter
private Timezone timeZone;
@Getter
@Setter
// @JSONField(serializeUsing=SupportAppNamesCodec.class, deserializeUsing=SupportAppNamesCodec.class)
private HashMap<String, Iterator<AppName>> supportAppNames;
public Device (String deviceNo, GradeWithValue grade) {
this.deviceNo = deviceNo;
this.grade = grade;
}
}
將反序列化邏輯封裝在自定義的 deserializer 和 serializer,並通過注解指定 fastjson 在序列化/反序列化的時候使用的工具類。這種方法代碼需根據實際業務修改,只是將原本的 JSON 字符串反序列化操作進行封裝,代碼無法覆用。
@JSONField(serializeUsing=SupportAppNamesCodec.class, deserializeUsing=SupportAppNamesCodec.class)
在類中添加某個 List 屬性時,為了不讓調用者直接通過引用修改數據,所以將 get 方法設計成返回一個不可變集合
返回 Iterable (記得要 disable the remove api, 其實就是 Collections.unmodifiableList) ,或者 Enumeration
在類中添加某個 List 屬性時,為了不讓調用者進行修改,所以在該屬性的 get 方法時實際返回的是一個 Iterable,即 List 所實現的一個接口,get 方法封裝了類對於該屬性的實現。因為 Iterable 接口中方法只包含用於遍歷的相關方法,不包含改變內部元素的方法。如果 get 方法返回的是 List 類型,那麽就暴露了類使用 List 來儲存該屬性,並且調用者可以簡單地通過得到的 List 對象來對類實例的內部數據進行修改,容易发生危險的事情。
返回 java.util.Collections.unmodifiableList,在下面的 stackexchange 里有說明。當一下搬運工。
public class Event {
private List<Player> players;
public List<Player> getPlayers() {
return Collections.unmodifiableList(players);
}
public void addPlayer(Player p) {
players.add(p);
}
}
返回 Guava's com.google.common.collect.ImmutableList (進一步保證了 thread-safe)
public ImmutableList<Timezone> getSupportedTimezone() {
return ImmutableList.copyOf(supportedTimezone);
}
另外,fastJson 不支持直接反序列化 ImmutableList。[3]
Exception in thread "main" com.alibaba.fastjson.JSONException: create instance error, class com.google.common.collect.ImmutableList
at com.alibaba.fastjson.util.TypeUtils.createCollection(TypeUtils.java:2082)
at com.alibaba.fastjson.parser.deserializer.FastjsonASMDeserializer_2_AppName.deserialze(Unknown Source)
at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:267)
at com.alibaba.fastjson.parser.DefaultJSONParser.parseArray(DefaultJSONParser.java:747)
at com.alibaba.fastjson.serializer.CollectionCodec.deserialze(CollectionCodec.java:129)
at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:661)
at com.alibaba.fastjson.parser.deserializer.MapDeserializer.parseMap(MapDeserializer.java:192)
at com.alibaba.fastjson.parser.deserializer.MapDeserializer.deserialze(MapDeserializer.java:59)
at com.alibaba.fastjson.parser.deserializer.MapDeserializer.deserialze(MapDeserializer.java:41)
at com.alibaba.fastjson.parser.deserializer.DefaultFieldDeserializer.parseField(DefaultFieldDeserializer.java:86)
at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.parseField(JavaBeanDeserializer.java:1078)
at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:773)
at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.parseRest(JavaBeanDeserializer.java:1283)
at com.alibaba.fastjson.parser.deserializer.FastjsonASMDeserializer_1_Device.deserialze(Unknown Source)
at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:267)
at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:661)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:365)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:269)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:488)
at serialization_tutorial.main.main(main.java:54)
Process finished with exit code 1
不要對 Iterable、ImmutableList 進行反序列化,非常反人類。直接在 get 方法返回你想要的數據形態就可以啦~ fastJson 解析 json 字符串的時候是首先根據 set 方法的數據形態,然後根據 field 的數據形態來決定的,而 get 方法貌似只要能正常得到數據都是可以的。